import fs from 'node:fs';
import path from 'node:path';
import { isType } from '../m.common.js';
import { s as srcExports } from '../external/vendor-ZVB4LWnE.js';

/**
 * 查看一个文件或目录是否在指定的路径下存在
 * @param { string } filename 文件名称
 * @param { string } cwd 工作目录，默认值为: 当前工作目录
 * @returns { boolean } 是否存在
 * **/
const exists = (filename, cwd = process.cwd()) => {
    return fs.existsSync(path.resolve(cwd, filename));
};
/**
 * 浅层读取一个目录下的文件或者文件夹
 * @param { string } targetPath 目标路径
 * @param { string } type 文件类型，默认值为: 全部类型
 * @return { Array<string> } 文件列表
 * **/
const readForTypeFileDir = (targetPath, type = 'all') => {
    const list = fs.readdirSync(targetPath);
    if (type === 'all')
        return list;
    return list.filter((item) => {
        const itemPath = path.resolve(targetPath, item);
        const stat = fs.statSync(itemPath);
        if (typeof type !== 'string')
            return type(itemPath, stat);
        return type === 'file' ? !stat.isDirectory() : stat.isDirectory();
    });
};
/**
 * 创建一个目录(仅支持目录)
 * @param { string } targetPath 目标路径
 * @param { boolean } cover 是否覆盖创建 默认值为: false
 * **/
const createDir = (targetPath, cover = false) => {
    if (fs.existsSync(targetPath)) {
        if (!cover)
            return;
        fs.rmSync(targetPath, { recursive: true });
    }
    fs.mkdirSync(targetPath, { recursive: true });
};
/**
 * 写入的一个文件(仅支持文件)
 * @param { string } targetPath 目标路径
 * @param { string } content 文件内容
 * @param { boolean } cover 是否覆盖创建，默认值为: false
 * **/
const createFile = (targetPath, content, cover = false) => {
    if (fs.existsSync(targetPath)) {
        if (!cover)
            return;
        fs.unlinkSync(targetPath);
    }
    const dirPathName = path.dirname(targetPath);
    if (!fs.existsSync(dirPathName))
        createDir(dirPathName);
    fs.writeFileSync(targetPath, content, { encoding: 'utf-8' });
};
/**
 * 当文件存在时，读取一个文件的文件内容
 * @param { string } targetPath 目标文件路径的
 * @param { Parameters<typeof fs.readFileSync>[1] } options 读取时需要传递的参数
 * @returns { string | Buffer } 返回的文件内容
 * **/
const readExistsFile = (targetPath, options = {}) => {
    if (!fs.existsSync(targetPath))
        return '';
    return fs.readFileSync(targetPath, options);
};
/**
 * 移动工具类，此方法仅适用文件的移动
 * @param { string } sourcePath 需要拷贝的路径
 * @param { string } targetPath 目标路径
 * @param { boolean } cover 是否强制覆盖
 * @returns { number } type 移动是否成功: 1 | 0
 * @returns { string } sourcePath 源路径
 * @returns { string } targetPath 目标路径
 * **/
const copyFile = (sourcePath, targetPath, cover = false) => {
    if (!fs.existsSync(targetPath) || cover) {
        fs.copyFileSync(sourcePath, targetPath);
        return { type: 1, sourcePath, targetPath };
    }
    return { type: 0, sourcePath, targetPath };
};
/**
 * 拷贝整个目录及其子路径至指定的目录
 * @param { string } origin 源路径
 * @param { string } targetPath 目标路径
 * @param { ((sourcePath: string, targetPath: string) => boolean) | boolean } cover 是否覆盖
 * @param { ((sourcePath: string, targetPath: string) => boolean) | boolean } ignore 是否忽略
 * **/
const copyDirectory = async (origin, targetPath, cover = true, ignore = false) => {
    const originStat = fs.statSync(origin).isDirectory();
    if (!originStat)
        throw new Error('origin or target is not directory');
    if (!fs.existsSync(targetPath))
        createDir(targetPath);
    const entries = fs.readdirSync(origin, { withFileTypes: true });
    for (const entry of entries) {
        const sourceChildrenPath = path.resolve(origin, entry.name), destChildrenPath = path.resolve(targetPath, entry.name);
        // 是否忽略此路径的移动
        if (typeof ignore === 'function' &&
            isType(ignore, ['function', 'asyncfunction']) &&
            (await ignore(sourceChildrenPath, destChildrenPath))) {
            continue;
        }
        // 此路径是否覆盖, 覆盖时，只能文件不能目录
        let isCover = false;
        if (fs.existsSync(destChildrenPath) && !entry.isDirectory()) {
            if ((isType(cover, ['boolean']) && cover) ||
                (typeof cover === 'function' &&
                    (await cover(sourceChildrenPath, destChildrenPath)))) {
                isCover = true;
                fs.unlinkSync(destChildrenPath);
            }
            else {
                continue;
            }
        }
        if (entry.isDirectory()) {
            await copyDirectory(sourceChildrenPath, destChildrenPath, cover, ignore);
        }
        else {
            copyFile(sourceChildrenPath, destChildrenPath, isCover);
        }
    }
};
/**
 * 移除文件, 当传递的是文件，则删除文件，传递的是目录，则递归删除目录
 * @param { string } targetPath 文件路径
 * */
const removeFileOrDir = (targetPath) => {
    if (!fs.existsSync(targetPath))
        return;
    const stats = fs.statSync(targetPath);
    if (stats.isDirectory())
        fs.rmSync(targetPath, { recursive: true });
    else
        fs.unlinkSync(targetPath);
};
/**
 * 检测权限，若权限不为读写，则赋值为读写
 * @param { string } targetPath 文件路径
 * **/
const checkXPermission = (targetPath) => {
    fs.accessSync(targetPath, fs.constants.X_OK);
    fs.chmodSync(targetPath, fs.constants.S_IXUSR);
};
/**
 * 检测文件是否为只读权限
 * @param { string } targetPath 文件路径
 * **/
const checkReadPermission = (targetPath) => {
    fs.accessSync(targetPath, fs.constants.R_OK);
};
/**
 * 递归删除目录, 手动方式删除（兼容老版本Node）
 * @param { string } dirPath 目录的路径
 * @param { Array<string> } whiteList 删除文件的白名单
 * **/
const dropCleanFolder = (dirPath, whiteList = []) => {
    if (fs.existsSync(dirPath)) {
        const files = fs.readdirSync(dirPath);
        for (const file of files) {
            const filePath = path.join(dirPath, file);
            if (fs.lstatSync(filePath).isDirectory()) {
                dropCleanFolder(filePath, whiteList);
            }
            else {
                if (!whiteList.includes(filePath)) {
                    fs.unlinkSync(filePath);
                }
            }
        }
        if (!whiteList.includes(dirPath)) {
            fs.rmdirSync(dirPath);
        }
    }
};
/**
 * 当文件存在时，则合并内容，反之创建文件
 * @param { string } source 源路径
 * @param { string } targetPath 目标路径
 * @param { Object } options 写入或创建文件的参数
 * **/
const mergeOrCreateFile = (source, targetPath, options = {}) => {
    options = srcExports.recursive({ wrap: false, jsonOrArray: false, tabWidth: 4 }, options);
    const existsSource = fs.existsSync(source), existsTarget = fs.existsSync(targetPath);
    if (!existsSource)
        throw new Error('source or target path can not be null');
    if (!existsTarget)
        return fs.copyFileSync(source, targetPath);
    const sourceContent = fs.readFileSync(source, { encoding: 'utf-8' });
    if (options.jsonOrArray) {
        const source = JSON.parse(sourceContent), target = JSON.parse(fs.readFileSync(targetPath, {
            encoding: 'utf-8'
        }));
        fs.writeFileSync(targetPath, JSON.stringify(srcExports.recursive(source, target), null, options.tabWidth), {
            encoding: 'utf-8'
        });
    }
    else {
        fs.appendFileSync(targetPath, `${options.wrap ? '\n' : ''}${sourceContent}`, { encoding: 'utf-8' });
    }
};
/**
 * 判断一个目录是否是盘符目录
 * @param { string } targetPath 目标路径
 * **/
const isDriveDirectory = (targetPath) => {
    targetPath = path.resolve(targetPath);
    return targetPath === path.parse(targetPath).root;
};
/**
 * 向上层目录层级执行一个函数，直到函数返回成功或遇到盘符目录为止
 * @param { string } targetPath 需要执行函数的目录
 * @param { Function } cb 执行的自定义函数, 此函数返回true则终止执行，反之执行至盘符目录为止
 * **/
const parentExecHandlerPromise = (targetPath, cb) => {
    return new Promise((resolve) => {
        if (isDriveDirectory(targetPath))
            return resolve('');
        const recursionExecHandler = () => resolve(parentExecHandlerPromise(path.dirname(targetPath), cb));
        if (isType(cb, 'asyncfunction')) {
            cb(targetPath)
                .then((result) => {
                if (!result)
                    throw new Error('');
                return resolve(result);
            })
                .catch(() => {
                return recursionExecHandler();
            });
        }
        else {
            try {
                const result = cb(targetPath);
                if (result)
                    return resolve(result);
                else
                    throw new Error('');
            }
            catch (e) {
                return recursionExecHandler();
            }
        }
    });
};
/**
 * 向上查询文件的存在目录
 * @param { string } targetPath 基准目录
 * @param { string } handler 文件名称或执行函数
 * @returns { string } 查询到的文件目录
 * **/
const findParentFile = (targetPath, handler) => {
    return parentExecHandlerPromise(targetPath, async (cwd) => {
        let result = null;
        if (isType(handler, 'string')) {
            result = fs.existsSync(path.resolve(cwd, handler));
        }
        else if (isType(handler, 'function')) {
            result = handler(cwd);
        }
        else if (isType(handler, 'asyncfunction')) {
            result = await handler(cwd);
        }
        else {
            throw new Error('invalid handler parameter');
        }
        return result ? cwd : result;
    });
};
/**
 * 给定一个目录，返回这个目录的根目录
 * @param { string } value 给定的目录字符串
 * @returns { string } 根目录字符串
 * **/
const findRootParentPath = (value) => {
    if (!value.trim())
        return value;
    value = value.replaceAll('//', '/');
    const parentPath = path.dirname(value);
    if (['.', '/'].includes(parentPath))
        return value;
    else
        return findRootParentPath(parentPath);
};
/**
 * 查看一个路径下是否存在列表中这些文件，只要有一个满足则返回 true
 * @param { string } basicPath 查询的路径
 * @param { Array<string> } fileNameList 需要查询的文件名称列表
 * @returns { string } 查询到的文件名称
 * **/
const getExistsFilePath = (basicPath = process.cwd(), fileNameList) => {
    for (const item of fileNameList) {
        const filePath = path.resolve(basicPath, item);
        if (fs.existsSync(filePath))
            return filePath;
    }
    return '';
};
/**
 * 将 blob 转换为 string 字符串
 * @param { Blob } blob 二进制数据内容
 * **/
const blobToString = (blob) => {
    return new Promise((resolve) => {
        const fileRender = new FileReader();
        fileRender.onload = () => {
            resolve(fileRender.result);
        };
        fileRender.readAsText(blob);
    });
};

export { blobToString, checkReadPermission, checkXPermission, copyDirectory, copyFile, createDir, createFile, dropCleanFolder, exists, findParentFile, findRootParentPath, getExistsFilePath, mergeOrCreateFile, readExistsFile, readForTypeFileDir, removeFileOrDir };
